package bg.unisofia.fmi.tis.service;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.validator.InvalidStateException;

import bg.unisofia.fmi.tis.model.Comment;
import bg.unisofia.fmi.tis.model.Identity;
import bg.unisofia.fmi.tis.model.Notification;
import bg.unisofia.fmi.tis.model.Role;
import bg.unisofia.fmi.tis.model.Thesis;
import bg.unisofia.fmi.tis.model.User;

public class ModelService {
	public static Identity save(Identity entity) {

        Session session = HibernateUtil.getSession();

        boolean bUseExternalTransaction = session.getTransaction().isActive();
        if (!bUseExternalTransaction) {
            session.getTransaction().begin();
        }

        Identity savedEntity = null;
        try {
            savedEntity = (Identity) session.merge(entity);

            if (!bUseExternalTransaction) {
                session.getTransaction().commit();
                System.out.println("Entity saved: " + savedEntity);
            }

        } catch (InvalidStateException ise) {
            ise.printStackTrace();
            if (!bUseExternalTransaction) {
                session.getTransaction().rollback();
            }
            throw ise;
        } catch (RuntimeException e) {
            e.printStackTrace();
            if (!bUseExternalTransaction) {
                session.getTransaction().rollback();
            }
            throw e;
        }

        return savedEntity;
    }

    /**
     * Deletes the specified enttity form DB.
     * @param entity - the entity to remove.
     */
    public static void delete(Identity entity) {

        Session session = HibernateUtil.getSession();

        boolean bUseExternalTransaction = session.getTransaction().isActive();
        if (!bUseExternalTransaction) {
            session.getTransaction().begin();
        }

        try {
            session.delete(entity);

            if (!bUseExternalTransaction) {
                session.getTransaction().commit();
                System.out.println("Entity deleted: " + entity);
            }

        } catch (InvalidStateException ise) {
            ise.printStackTrace();
            if (!bUseExternalTransaction) {
                session.getTransaction().rollback();
            }
            throw ise;
        } catch (RuntimeException e) {
            e.printStackTrace();
            if (!bUseExternalTransaction) {
                session.getTransaction().rollback();
            }
            throw e;
        }
    }

    /**
     * Loads an entity by its id.
     * @param <T> - the type to load.
     * @param clazz - the Class object of what is to be loaded.
     * @param id - the id to load by.
     * @return - an entity with this id and type. Null is returned if no such entity exists in DB.
     */
    public static <T extends Identity> T findById(Class<T> clazz, Integer id) {
        Session session = HibernateUtil.getSession();

        try {

            Query query = session.createQuery("from " + clazz.getName() + " cs where id = " + id);
            query.setMaxResults(1);

            List<T> result = query.list();
            if (result == null || result.isEmpty()) {
                return null;
            }
            return result.get(0);
        } catch (JDBCConnectionException jdbcce) {
            throw jdbcce;
        }
    }

    /**
     * Loads an entity by its name.
     * @param <T> - the type to load.
     * @param clazz - the Class object of what is to be loaded.
     * @param name - the name of the class.
     * @return - an entity with this name and type. Null is returned if no such entity exists in DB.
     */
    public static <T extends Identity> T findByName(Class<T> clazz, String name) {
        Session session = HibernateUtil.getSession();

        try {

            Query query = session.createQuery("from " + clazz.getName() + " cs where name = '" + name + "'");
            query.setMaxResults(1);

            List<T> result = query.list();
            if (result == null || result.isEmpty()) {
                return null;
            }
            return result.get(0);
        } catch (JDBCConnectionException jdbcce) {
            throw jdbcce;
        }
    }

    /**
     * Returns all entities from the specified type.
     * @param <T> - the type to load.
     * @param entityClass - the Class object of what is to be loaded.
     * @return a list of all entities from the specified type.
     */
    public static <T> List<T> getAll(Class<? extends Identity> entityClass) {
        Session session = HibernateUtil.getSession();

        try {
            List<T> result =
                    (List<T>) session.createQuery("from " + entityClass.getName() + " c").list();
            return result;
        } catch (JDBCConnectionException jdbcce) {
            throw jdbcce;
        }
    }
    
    public static List<Notification> loadNotifications(User user) {
    	 Session session = HibernateUtil.getSession();

         try {

             Query query = session.createQuery("from Notification cs where forUser = :user");
             query.setParameter("user", user);

             List<Notification> result = query.list();
             if (result == null || result.isEmpty()) {
                 return null;
             }
             return result;
         } catch (JDBCConnectionException jdbcce) {
             throw jdbcce;
         }
    }
    
    public static Comment getLastComment(Thesis thesis) {
    	Session session = HibernateUtil.getSession();

        try {
            Query query = session.createQuery("from Comment c where thesis = :thesis order by id desc");
            query.setParameter("thesis", thesis);
            query.setMaxResults(1);

            List<Comment> result = query.list();
            if (result == null || result.isEmpty()) {
                return null;
            }
            return result.get(0);
        } catch (JDBCConnectionException jdbcce) {
            throw jdbcce;
        }
    }
    
    public static List<User> findAllTeachers() {
    	Session session = HibernateUtil.getSession();

        try {
            Query query = session.createQuery("from User u where role = :role");
            query.setParameter("role", Role.TEACHER);
            query.setMaxResults(1);

            List<User> result = query.list();
            if (result == null || result.isEmpty()) {
                return null;
            }
            return result;
        } catch (JDBCConnectionException jdbcce) {
            throw jdbcce;
        }
    }
}
